/*
 * @Author         : zhanglk
 * @Date           : 2020-05-29 14:21:20
 * @LastEditTime   : 2020-08-25 11:06:49
 * @LastEditors    : zhanglk
 * @Description    :
 * @FilePath       : \jiaparts-jsj\src\utils\index.ts
 */
import Toast from '@/utils/toast';
import { useOssStore } from '@/store/oss'
let ossStore : any = {}
import defaultConfig from "@/config";
import {
	Ref,
	UnwrapRef,
	ref,
	reactive
} from "vue"

/**
 * 小程序公共方法库
 */
//当前是否为开发环境
export const isDev = () => {
	return process.env.NODE_ENV === 'development';
};

//是否为中文
export const isChinese = (str : string) => {
	if (escape(str).indexOf('%u') < 0) return false;
	return true;
};


//获取某一时间的月首时间戳
export const getMonthStart = (
	time : number | string,
) : number => {
	let date = timeToDate(time);
	let year = date.getFullYear();
	let month = date.getMonth();
	let monthDate = new Date(year, month);
	return monthDate.getTime();
}
//获取某一时间的月末时间戳
export const getMonthEnd = (
	time : number | string,
) : number => {
	let date = timeToDate(time);
	let year = date.getFullYear();
	let month = date.getMonth();
	let monthDate = new Date(year, month + 1);
	return monthDate.getTime();
}

//时间码或时间字符串转日期对象
export const timeToDate = (
	time ?: number | string
) : Date => {
	if (!isNotEmpty(time)) {
		return new Date();
	}

	let date : any;
	if (typeof time == 'number') {
		if (time.toString().length <= 10) {
			time = time * 1000;
		}
		date = new Date(time);
	} else if (typeof time == 'string') {
		date = new Date(Date.parse(time.replace(/-/g, '/')));
	}
	return date;
}

//日期格式化
export const formatTime = (
	time ?: number | string,
	fmt : string = 'yyyy-MM-dd hh:mm'
) : string => {
	let date : any = timeToDate(time);
	if (/(y+)/.test(fmt)) {
		fmt = fmt.replace(
			RegExp.$1,
			(date.getFullYear() + '').substr(4 - RegExp.$1.length)
		);
	}
	let o = {
		'M+': date.getMonth() + 1,
		'd+': date.getDate(),
		'h+': date.getHours(),
		'm+': date.getMinutes(),
		's+': date.getSeconds()
	};
	for (let k in o) {
		if (new RegExp(`(${k})`).test(fmt)) {
			let str = o[k] + '';
			fmt = fmt.replace(
				RegExp.$1,
				RegExp.$1.length === 1 ? str : formatNumber(str)
			);
		}
	}
	return fmt;
};
//数字前加0
export const formatNumber = n => {
	n = n.toString();
	return n[1] ? n : '0' + n;
};

export function formateSecond(timespan : number) {
	if (timespan.toString().length <= 10) {
		timespan = timespan * 1000;
	}
	let dateTime = new Date(timespan);

	// let year = dateTime.getFullYear();
	// let month = dateTime.getMonth() + 1;
	let day = dateTime.getDate();
	// let hour = dateTime.getHours();
	// let minute = dateTime.getMinutes();
	// let second = dateTime.getSeconds();
	let now = new Date();
	let now_new : number = Date.now();
	let offset = Math.abs(now.getDate() - day);

	let milliseconds = 0;
	let timeSpanStr;

	milliseconds = now_new - timespan;
	if (milliseconds <= 1000 * 60 * 1) {
		timeSpanStr = '刚刚';
	} else if (1000 * 60 * 1 < milliseconds && milliseconds <= 1000 * 60 * 60) {
		timeSpanStr = Math.round(milliseconds / (1000 * 60)) + '分钟前';
		// timeSpanStr = formatTime(timespan, "hh:mm");
	} else if (
		1000 * 60 * 60 * 1 < milliseconds &&
		milliseconds <= 1000 * 60 * 60 * 24 &&
		offset == 0
	) {
		// timeSpanStr = Math.round(milliseconds / (1000 * 60 * 60)) + "小时前";
		timeSpanStr = formatTime(timespan, 'hh:mm');
	} else if (offset == 1) {
		// timeSpanStr = Math.round(milliseconds / (1000 * 60 * 60 * 24)) + '天前';
		timeSpanStr = '昨天' + formatTime(timespan, 'hh:mm');
	}
	//大于2天
	else if (milliseconds > 1000 * 3600 * 24 * 2) {
		timeSpanStr = formatTime(timespan, 'yyyy-MM-dd');
	}
	return timeSpanStr;
}

export function transDate(timestamp : number) {
	let tt = new Date(timestamp);
	let days = (new Date().getTime() - timestamp) / 86400000;
	let today = new Date().getDate();
	let year = tt.getFullYear();
	let mouth = tt.getMonth() + 1;
	let day = tt.getDate();
	let time = tt.getHours() < 10 ? '0' + tt.getHours() : tt.getHours();
	let min = tt.getMinutes() < 10 ? '0' + tt.getMinutes() : tt.getMinutes();
	let result;
	let offset;
	offset = Math.abs(today - day);

	if (days < 4 && offset < 4) {
		if (offset === 0) {
			result = '今天' + time + ':' + min;
		} else if (offset === 1) {
			result = '昨天' + time + ':' + min;
		} else if (offset === 2) {
			result = '前天' + time + ':' + min;
		}
	} else {
		result = year + '-' + mouth + '-' + day + ' ' + time + ':' + min;
	}
	return result;
}

/**
 * 通过oss key 获取url
 * @param fileKey
 */
export const getOssFileUrl = (fileKey : string, refresh : boolean = true) => {
	if (!ossStore.upOss) {
		ossStore = useOssStore()
	}
	let host = ossStore.upOss;
	return refresh ? `${host}/${fileKey}?r=${Date.now()}` : `${host}/${fileKey}`;
};

/**
 * 根据机构id获取图像
 * @param organId
 */
export const getOrganLogo = (organId : number, refresh : boolean = true) => {

	let fileKey = `logo/organ/${organId}_logo`;
	return getOssFileUrl(fileKey, refresh);
};

/**
 * 根据用户id获取图像
 * @param organId
 */
export const getUserLogo = (userId : string | number) => {
	if (!ossStore.upOss) {
		ossStore = useOssStore()
	}
	let host = ossStore.upOss;
	return `${host}/logo/user/${userId}_logo?r=${Date.now()}`;
};

/**
 * 根据用户id获取微信二维码
 * @param userId
 */
export const getWechatLogo = (userId : string | number) => {
	if (!ossStore.upOss) {
		ossStore = useOssStore()
	}
	let host = ossStore.upOss;
	return `${host}/logo/wechat/${userId}_logo?r=${Date.now()}`;
};

/**
 * 截取字符串
 */
export function cutWord(str, len) {
	if (str && str.length > len) {
		return str.slice(0, len) + '...';
	} else {
		return str;
	}
}

//接口统一判断方法
export const getMsg = (res : any) => {
	if (res.retCode == '200' || res.retCode == 200) {
		return true;
	} else if (res.retCode == '300' || res.retCode == 300) {
		Toast.message(
			res === undefined || res === null ? '接口未知异常' : res.retMsg
		);
		return false;
	} else {
		Toast.message(
			res === undefined || res === null ? '接口未知异常' : res.retMsg
		);
		return false;
	}
};

export const priceFmt = (val : number) => {
	return val.toString().indexOf('.') > 0 ? val.toFixed(2) : val + '.00';
};

///判断是否为合法的JSON字符串
export const isJSON = (str : any) : boolean => {
	if (!isNotEmpty(str)) return false;
	try {
		JSON.parse(str);
	} catch (e) {
		// 转换出错，抛出异常
		return false;
	}
	return true;
}

///判断是否为空
export const isNotEmpty = (str : any) : boolean => {
	if (typeof str === 'string') {
		if (
			str == undefined ||
			str == null ||
			str == '' ||
			str == 'undefined' ||
			str == 'null'
		) {
			return false;
		}
	} else {
		if (str == undefined || str == null) {
			return false;
		}
	}

	return true;
};
export const getImageFromMake = (str : string | number) : string => {
	return getOssFileUrl('logo/carlogo/' + str + '.png');
};


/**
 * @description: 隐藏号码加*
 * @param {head：开头显示几位，end：结尾显示几位}
 * @return:
 */
export function formateNumber(value : string, head : number, end : number) {
	if (!value || value == undefined) return '';
	let reg = new RegExp(`(.{${head}}).*(.{${end}})`);
	return value.replace(reg, '$1****$2');
}

/** 
* 加法运算，避免数据相加小数点后产生多位数和计算精度损失。 
* 
* @param num1加数1 | num2加数2 
*/
export function numAdd(num1 : number, num2 : number) {
	let baseNum, baseNum1, baseNum2;
	try {
		baseNum1 = num1.toString().split(".")[1].length;
	} catch (e) {
		baseNum1 = 0;
	}
	try {
		baseNum2 = num2.toString().split(".")[1].length;
	} catch (e) {
		baseNum2 = 0;
	}
	baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
	return (num1 * baseNum + num2 * baseNum) / baseNum;
};
/** 
* 减法运算，避免数据相减小数点后产生多位数和计算精度损失。 
* 
* @param num1被减数 | num2减数 
*/
export function numSub(num1, num2) {
	console.log(num1, num2)
	let baseNum, baseNum1, baseNum2;
	let precision;// 精度 
	try {
		baseNum1 = num1.toString().split(".")[1].length;
	} catch (e) {
		baseNum1 = 0;
	}
	try {
		baseNum2 = num2.toString().split(".")[1].length;
	} catch (e) {
		baseNum2 = 0;
	}
	baseNum = Math.pow(10, Math.max(baseNum1, baseNum2));
	precision = (baseNum1 >= baseNum2) ? baseNum1 : baseNum2;
	return ((num1 * baseNum - num2 * baseNum) / baseNum).toFixed(precision);
};
/** 
* 乘法运算，避免数据相乘小数点后产生多位数和计算精度损失。 
* 
* @param num1被乘数 | num2乘数 
*/
export function numMulti(num1, num2) {
	let baseNum = 0;
	try {
		baseNum += num1.toString().split(".")[1].length;
	} catch (e) {
	}
	try {
		baseNum += num2.toString().split(".")[1].length;
	} catch (e) {
	}
	return Number(num1.toString().replace(".", "")) * Number(num2.toString().replace(".", "")) / Math.pow(10, baseNum);
};
/** 
* 除法运算，避免数据相除小数点后产生多位数和计算精度损失。 
* 
* @param num1被除数 | num2除数 
*/
export function numDiv(num1, num2) {
	let baseNum1 = 0, baseNum2 = 0;
	let baseNum3, baseNum4;
	try {
		baseNum1 = num1.toString().split(".")[1].length;
	} catch (e) {
		baseNum1 = 0;
	}
	try {
		baseNum2 = num2.toString().split(".")[1].length;
	} catch (e) {
		baseNum2 = 0;
	}
	baseNum3 = Number(num1.toString().replace(".", ""));
	baseNum4 = Number(num2.toString().replace(".", ""));
	return (baseNum3 / baseNum4) * Math.pow(10, baseNum2 - baseNum1);
};
/**
 * 
 * @param timer 
 * @param format 
 */
export const formatTimeSplit = (timer : number, isOnlyDay : boolean = false) : any => {
	// diffTime此为时间戳相减的时间差
	let now = new Date().getTime() / 1000;
	let second = timer - now;
	let minute = 0;
	let hour = 0;
	let day = 0
	let result = ``;
	// 将秒数转换成整数
	if (second < 1) {
		return -1;
	} else if (isOnlyDay) {
		let oneDay = 24 * 60 * 60;
		let day = Math.floor(second / oneDay)
		let hour = Math.floor(second % oneDay);
		if (hour > 0) {
			day++;
		}
		return day;
	} else {
		//  获取分钟
		minute = Math.floor(second / 60);
		//  获取秒数
		second = Math.floor(second % 60);
		//  如果分钟大于60，将分钟转换成小时
		if (minute > 60) {
			//  获取小时，获取分钟除以60，
			hour = Math.floor(minute / 60);
			// 获取分钟除以60取佘的分
			minute = Math.floor(minute % 60);
			//  如果小时大于24，将小时转换成天
			if (hour > 23) {
				day = Math.floor(hour / 24)
				hour = Math.floor(hour % 24)
			}
		}
		if (minute > 0) {
			result = `${minute}分${result}`;
		}
		if (hour > 0) {
			result = `${hour}小时${result}`;
		}
		if (day > 0) {
			result = '' + Math.floor(day) + '天' + result
		}
		return result;
	}
};

//比较版本号
//compareVersion('1.11.0', '1.9.9') // 1
export function compareVersion(v1 : string, v2 : string) {
	v1 = v1.split('.')
	v2 = v2.split('.')
	const len = Math.max(v1.length, v2.length)

	while (v1.length < len) {
		v1.push('0')
	}
	while (v2.length < len) {
		v2.push('0')
	}

	for (let i = 0; i < len; i++) {
		const num1 = parseInt(v1[i])
		const num2 = parseInt(v2[i])

		if (num1 > num2) {
			return 1
		} else if (num1 < num2) {
			return -1
		}
	}
	return 0
};

/*身份证验证输入是否正确
 *身份证号合法性验证
*支持15位和18位身份证号 *支持地址编码、出生日期、校验位验证*/
export function getBirthAndSex(value : string) {
	let code = value;//identity 为你输入的身份证
	console.log("身份证===" + code);
	let city = { 11: "北京", 12: "天津", 13: "河北", 14: "山西", 15: "内蒙古", 21: "辽宁", 22: "吉林", 23: "黑龙江 ", 31: "上海", 32: "江苏", 33: "浙江", 34: "安徽", 35: "福建", 36: "江西", 37: "山东", 41: "河南", 42: "湖北 ", 43: "湖南", 44: "广东", 45: "广西", 46: "海南", 50: "重庆", 51: "四川", 52: "贵州", 53: "云南", 54: "西藏 ", 61: "陕西", 62: "甘肃", 63: "青海", 64: "宁夏", 65: "新疆", 71: "台湾", 81: "香港", 82: "澳门", 91: "国外 " };
	let tip = "";
	let pass = true;
	let reg = /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/;
	if (!code || !code.match(reg)) {
		tip = "身份证号格式错误";
		pass = false;
	} else if (!city[code.substr(0, 2)]) {
		tip = "地址编码错误"; pass = false;
	} else {
		//18位身份证需要验证最后一位校验位
		if (code.length == 18) {
			code = code.split('');
			//∑(ai×Wi)(mod 11)
			//加权因子
			let factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
			//校验位
			let parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2];
			let sum = 0;
			let ai = 0;
			let wi = 0;
			for (let i = 0; i < 17; i++) {
				ai = code[i];
				wi = factor[i];
				sum += ai * wi;
			}
			let last = parity[sum % 11];
			if (parity[sum % 11] != code[17]) {
				tip = "校验位错误";
				pass = false;
			}
		}
	}
	console.log("身份证===" + pass);
	return pass;
}


// 定义一些常量
/* eslint-disable */
var PI = 3.1415926535897932384626
var a = 6378245.0
var ee = 0.00669342162296594323
/**
 * WGS84转GCj02
 * @param lng
 * @param lat
 * @returns {*[]}
 */
export function wgs84togcj02(lng, lat) {
	var lat = +lat
	var lng = +lng
	if (out_of_china(lng, lat)) {
		return [lng, lat]
	} else {
		var dlat = transformlat(lng - 105.0, lat - 35.0)
		var dlng = transformlng(lng - 105.0, lat - 35.0)
		var radlat = lat / 180.0 * PI
		var magic = Math.sin(radlat)
		magic = 1 - ee * magic * magic
		var sqrtmagic = Math.sqrt(magic)
		dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI)
		dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI)
		var mglat = lat + dlat
		var mglng = lng + dlng
		return [mglng, mglat]
	}
}
var transformlat = function transformlat(lng, lat) {
	var lat = +lat
	var lng = +lng
	var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng))
	ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0
	ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0
	ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0
	return ret
}
var transformlng = function transformlng(lng, lat) {
	var lat = +lat
	var lng = +lng
	let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng))
	ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0
	ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0
	ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0
	return ret
}
/**
 * 判断是否在国内，不在国内则不做偏移
 * @param lng
 * @param lat
 * @returns {boolean}
 */
var out_of_china = function out_of_china(lng, lat) {
	lat = +lat
	lng = +lng
	// 纬度3.86~53.55,经度73.66~135.05
	return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55)
}

export function gcj02towgs84(lng, lat) {
	var lat = +lat
	var lng = +lng
	if (out_of_china(lng, lat)) {
		return [lng, lat]
	} else {
		var dlat = transformlat(lng - 105.0, lat - 35.0)
		var dlng = transformlng(lng - 105.0, lat - 35.0)
		var radlat = lat / 180.0 * PI
		var magic = Math.sin(radlat)
		magic = 1 - ee * magic * magic
		var sqrtmagic = Math.sqrt(magic)
		dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI)
		dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI)
		var mglat = lat + dlat
		var mglng = lng + dlng
		return [lng * 2 - mglng, lat * 2 - mglat]
	}
}

export const checkLogin = () => {
	//app.vue判断了登录权限 如果页面中又调此方法判断 会导致跳转登录页两次
	//本来此方法注释了的，又发现新的问题,在登录页点击左上角去首页图标，回到了回到了首页(本来首页是需要登录的)
	//原因是现在是app.vue onshow判断是否登录，左上角去首页图标回首页是不会触发app.vue onshow方法的
	//所以只能在首页调用checklogin方法
	//最上面说了页面调用此方法，会跟app.vue中冲突，导致如果是从公众号菜单打开调用此
	//方法的页面，会导致跳转登录页两次，所以只能在app.vue中过滤此页面。方法就是将页面地址
	//加入到config/index中的notLoginPage中
	let data = uni.getStorageSync(defaultConfig.loginKey);
	if (!data) {
		console.log('reLaunch11222')
		uni.reLaunch({
			url: '/pages/login/bind-mobile'
		});
		return;
	}
}


let _ = {
	now:
		Date.now ||
		function () {
			return new Date().getTime();
		},
};
/**
 * 频率控制 返回函数连续调用时，func 执行频率限定为 次 / wait
 *
 * @param  {function}   func      传入函数
 * @param  {number}     wait      表示时间窗口的间隔
 * @param  {object}     options   如果想忽略开始边界上的调用，传入{leading: false}。
 *                                如果想忽略结尾边界上的调用，传入{trailing: false}
 * @return {function}             返回客户调用函数
 */
export function throttle(func : (...args : any[]) => any, wait : number, options : any) {
	let context : any, args : any, result : any;
	let timeout : any = null;
	let previous = 0;
	if (!options) options = {};
	var later = function () {
		previous = options.leading === false ? 0 : _.now();
		timeout = null;
		result = func.apply(context, args);
		if (!timeout) context = args = null;
	};
	return function () {
		var now = _.now();
		if (!previous && options.leading === false) previous = now;
		var remaining = wait - (now - previous);
		context = this;
		args = arguments;
		if (remaining <= 0 || remaining > wait) {
			if (timeout) {
				clearTimeout(timeout);
				timeout = null;
			}
			previous = now;
			result = func.apply(context, args);
			if (!timeout) context = args = null;
		} else if (!timeout && options.trailing !== false) {
			timeout = setTimeout(later, remaining);
		}
		return result;
	};
}
/**
 * 空闲控制 返回函数连续调用时，空闲时间必须大于或等于 wait，func 才会执行
 *
 * @param  {function} func        传入函数
 * @param  {number}   wait        表示时间窗口的间隔
 * @param  {boolean}  immediate   设置为ture时，调用触发于开始边界而不是结束边界
 * @return {function}             返回客户调用函数
 */
export function debounce(func : (...args : any[]) => any, wait : number, immediate = false) {
	let timeout : any, args : any, context : any, timestamp : any, result : any;

	let later = function () {
		let last = _.now() - timestamp;

		if (last < wait && last >= 0) {
			timeout = setTimeout(later, wait - last);
		} else {
			timeout = null;
			if (!immediate) {
				result = func.apply(context, args);
				if (!timeout) context = args = null;
			}
		}
	};

	return function () {
		context = this;
		args = arguments;
		timestamp = _.now();
		let callNow = immediate && !timeout;
		if (!timeout) timeout = setTimeout(later, wait);
		if (callNow) {
			result = func.apply(context, args);
			context = args = null;
		}

		return result;
	};
}

/**
 * asyncOnce函数，接受一个异步函数作为参数
 * 返回一个新的函数,新的函数同时只能被调用一次，多次调用只返回第一次调用结果
 * isSameTime:ture时同时请求才会只调用一次
 */
export function asyncOnce(
	cb : (...args : any[]) => Promise<any>,
	isSameTime : boolean = true
) {
	const map : Record<
		string,
		{
			resolves : ((res : any) => void)[];
			rejects : ((err : any) => void)[];
			isPending : boolean;
			res : any;
		} | null
	> = {};
	return (...args : any) => {
		return new Promise((resolve, reject) => {
			const key = JSON.stringify(args);
			if (!map[key]) {
				map[key] = {
					resolves: [],
					rejects: [],
					isPending: false,
					res: null,
				};
			}
			const state = map[key]!;
			state.resolves.push(resolve);
			state.rejects.push(reject);
			if (state.isPending) {
				return;
			}
			if (!isSameTime && state.res) {
				state.resolves.forEach((resolve) => resolve(state.res));
				return;
			}
			state.isPending = true;
			cb(...args)
				.then((res) => {
					state.res = res;
					state.resolves.forEach((resolve) => resolve(res));
				})
				.catch((err) => {
					state.rejects.forEach((reject) => reject(err));
				})
				.finally(() => {
					map[key]!.isPending = false;
					if (isSameTime) {
						map[key] = null;
					}
				});
		});
	};
}


export function isXLSQ() {
	return defaultConfig.module == 'XLBUY'
}

function defaultClone(value : any) {
	if (value === null || typeof value != "object") return value;
	return JSON.parse(JSON.stringify(value));
}

/**
 * 创建可重置的ref对象
 * @param value
 * @param clone
 * @returns
 */
export function useResettableRef<T>(
	value : T,
	clone = defaultClone
) : [Ref<UnwrapRef<T>>, Function] {
	const initialValue = clone(value);
	const state = ref(value);
	const reset = () => {
		state.value = clone(initialValue);
	};
	return [state, reset];
}

/**
 * 创建可重置的reactive对象
 * @param value
 * @param clone
 * @returns
 */
export function useResettableReactive<T extends object>(
	value : T,
	clone = defaultClone
) : [T, Function] {
	const state = reactive(clone(value)) as T;
	const reset = () => {
		Object.keys(state).forEach((key) => {
			delete state[key];
		});
		Object.assign(state, clone(value));
	};
	return [state, reset];
}